package com.helsmanli.holiday.util;

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.lmj.holiday.model.WeekDay;

/**
 * <p>
 *	内容处理工具类
 * </p>
 *
 * @author helsmanli
 * @description
 * @date 2022/3/7
 */
public class EventUtil {

    private static final String HOLIDAY_TEMPLATE = HolidayPropertyUtil.get("holiday.template");
    private static final String WORKDAY_TEMPLATE = HolidayPropertyUtil.get("workday.template");
    private static final String[] NIAN_YUE_RI_ZHI_ETC = HolidayPropertyUtil.get("nian.yue.ri.zhi.etc").split(",");
    private static final String SEARCH_REG_PREFIX = HolidayPropertyUtil.get("search.reg.prefix");
    private static final int[] YEAR_MONTH_DATE = new int[NIAN_YUE_RI_ZHI_ETC.length];

    private EventUtil() {
    }

    /**
     * Get all holiday events, one day map to one event.
     *
     * @param holidayContent one line holiday content.
     * @return all holiday events.
     * @throws Exception 
     */
    protected static List<WeekDay> getEvents(List<String> holidayContent, String link) throws Exception {
        List<WeekDay> events = new ArrayList<>();
        String name = holidayContent.get(0);
        StringBuilder description = new StringBuilder(String.join("，", holidayContent.subList(0, 3)));
        description.append(holidayContent.size() >= 4 ? "\n" + holidayContent.get(3) : "");
        //description.append("\n\n").append(link);

        // Add all holiday events.
        addEvents(events, HOLIDAY_TEMPLATE, name, holidayContent.get(1), description.toString(), link);
        // Add all workday events.
        if (holidayContent.size() >= 4) {
            addEvents(events, WORKDAY_TEMPLATE, name, holidayContent.get(3), description.toString(), link);
        }

        return events;
    }

    /**
     * Get dates from holiday content, then create event from date and add to events list.
     *
     * @param events  the final events list.
     * @param content the holiday content.
     * @param name    the event name.
     * @throws Exception 
     */
    private static void addEvents(List<WeekDay> events, String summaryTemplate, String name, String content, String description, String link) throws Exception {
        List<LocalDate> dates = getDates(content, link);
        int cnt = 0;
        for (LocalDate date : dates) {
            cnt++;
            events.add(new WeekDay(date, String.format(summaryTemplate, name, cnt, dates.size()), "", description, ""));
        }
    }

    /**
     * Get all dates from holiday content.
     *
     * @param content the holiday content.
     * @return holiday or work dates.
     * @throws Exception 
     */
    private static List<LocalDate> getDates(String content, String link) throws Exception {
        String originContent = content;
        List<LocalDate> dates = new ArrayList<>();
        while (Arrays.stream(NIAN_YUE_RI_ZHI_ETC).anyMatch(content::contains)) {
            String[] ss;
            for (int i = 0; i < NIAN_YUE_RI_ZHI_ETC.length; i++) {
                ss = content.split(NIAN_YUE_RI_ZHI_ETC[i], 2);
                if (ss.length != 2) {
                	// todo 这里逻辑有问题
                	// 防止这种情况：2018年12月30日至2019年1月1日放假调休，共3天。2018年12月29日（星期六）上班。
                	// 获取2019年节假日，日期为2018
                	if("年".equals(NIAN_YUE_RI_ZHI_ETC[i])) {
                		YEAR_MONTH_DATE[i] = getPubYear(link);
                	}
                    continue;
                }
                if (!ss[0].isEmpty()) {
                    YEAR_MONTH_DATE[i] = Integer.parseInt(ss[0]);
                }
                content = ss[1];
            }
            dates.add(LocalDate.of(YEAR_MONTH_DATE[0], YEAR_MONTH_DATE[1], YEAR_MONTH_DATE[2]));
        }

        return originContent.contains(NIAN_YUE_RI_ZHI_ETC[3]) ? expandDates(dates) : dates;
    }

    /**
     * Get all dates between origin dates.
     *
     * @param originDates the dates need to be expanded.
     * @return expanded dates.
     */
    private static List<LocalDate> expandDates(List<LocalDate> originDates) {
        List<LocalDate> dates = new ArrayList<>();

        LocalDate start = null;
        for (LocalDate date : originDates) {
            if (start != null) {
                dates.addAll(datesUntil(start, date));
            }
            start = date;
        }
        dates.add(start);

        return dates;
    }

    private static List<LocalDate> datesUntil(LocalDate start, LocalDate end) {
        // 获取天数
        long numOfDays = ChronoUnit.DAYS.between(start, end);
        return Stream.iterate(start, date -> date.plusDays(1))
                .limit(numOfDays)
                .collect(Collectors.toList());
    }

    /**
     * 获取发布时间的下一年
     * @param link
     * @return
     * @throws Exception
     */
    protected static int getPubYear(String link) throws Exception {
    	 int pubYear = 0;
         try {
         	 String pubDate = link.replace(SEARCH_REG_PREFIX, "").split("/")[0];
              pubYear = Integer.valueOf(pubDate.split("-")[0]) + 1;
 		} catch (Exception e) {
 			throw new Exception("非法网址");
 		}
    	return pubYear;
    }
}
